import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import entity.pull.*;
import entity.push.BasePushDto;
import entity.push.PushUserDto;
import entity.push.LoginAndOut;
import entity.push.PushMsgDto;
import entity.service.ImgDto;
import entity.service.UserDto;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import utils.WsUtil;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;


public class MyWebSocketHandler extends SimpleChannelInboundHandler<Object> {


    //分组容器
    private static ConcurrentMap<Integer, ConcurrentMap<String, Channel>> channelMap = new ConcurrentHashMap<>();
    //channelid所在的组
    private static ConcurrentMap<String , UserDto> channelByGroup =new ConcurrentHashMap<>();
    //画板缓存
    private static ConcurrentMap<Integer , ArrayList<PullCanvasDto>>canvse= new ConcurrentHashMap<>();
    //背景图片缓存
    private static ConcurrentMap<Integer , ImgDto> img = new ConcurrentHashMap<>();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
        //文本消息
        if (msg instanceof TextWebSocketFrame) {
            TextWebSocketFrame text=  (TextWebSocketFrame)msg;
            System.out.println(text.text());

            Integer type=null;
            String date=null;
            try {
                JSONObject jsonObject = JSON.parseObject(text.text());
                type=Integer.valueOf(jsonObject.get("type").toString());
                if(null!=jsonObject.get("data")){
                    date= jsonObject.get("data").toString();
                }
               }catch (Exception e){ctx.close();}
            if(type==null){
                ctx.close();
            }


            //登录
            if(type==1){
                LoginHandler(ctx,JSON.parseObject(date,LoginDto.class));
            }

           else {
                UserDto userDto = channelByGroup.get(ctx.channel().id().asLongText());
                //发送消息
                if (type == 2) {
                    MsgHandler(userDto,ctx, JSON.parseObject(date, PullMsgDto.class));
                }
                //画板动作
                else if (type == 3) {
                    CanvasHandler(userDto,ctx, JSON.parseObject(date, PullCanvasDto.class));
                }
                //拉取画板缓存
                else if (type == 4 ){
                    ArrayList<PullCanvasDto> set = canvse.get(userDto.getGroup());
                    BasePushDto send = new BasePushDto();
                    send.setType(5);
                    if(set!=null){
                        for (PullCanvasDto s : set) {
                            send.setData(s);
                            ctx.writeAndFlush(new TextWebSocketFrame( JSON.toJSONString(send)));
                        }
                    }
                }
                //切背景图
                else if(type == 5){
                    ChangeImgHandler(userDto,ctx, JSON.parseObject(date, ChangeImgDto.class));
                }
                //移动背景图
                else if(type == 6){
                    MoveImgHandler(userDto,ctx, JSON.parseObject(date, MoveImgDto.class));
                }
                //清除自己的画板
                else if(type == 7){
                    ClearUsHandler(userDto,ctx);
                    //清空所有画板
                }else if(type == 8 ){
                    ClearAllHandler(userDto,ctx);
                }
                //拉取背景图片缓存
                else if(type ==9){
                    BasePushDto send = new BasePushDto();
                    send.setType(10);
                    send.setData(img.get(userDto.getGroup()));
                    ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(send)));
                }

            }
        }
        //二进制消息
        if (msg instanceof BinaryWebSocketFrame) {
            System.out.println("收到二进制消息：" + ((BinaryWebSocketFrame) msg).content().readableBytes());
            BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(Unpooled.buffer().writeBytes("hello".getBytes()));
            //给客户端发送的消息
            ctx.channel().writeAndFlush(binaryWebSocketFrame);
        }
        //ping消息
        if (msg instanceof PongWebSocketFrame) {
            System.out.println("客户端ping成功");
        }
        //关闭消息
        if (msg instanceof CloseWebSocketFrame) {
            System.out.println("客户端关闭，通道关闭");
            Channel channel = ctx.channel();
            channel.close();
        }
    }
    //掉线消息
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        UserDto userDto = channelByGroup.get(ctx.channel().id().asLongText());
        //关闭连接
        channelByGroup.remove(ctx.channel().id().asLongText());

        //通知掉线
        ConcurrentMap<String, Channel> channelConcurrentMap = channelMap.get(userDto.getGroup());
        channelConcurrentMap.remove(userDto.getUserid());
        BasePushDto send = new BasePushDto();
        send.setType(4);
        LoginAndOut loginAndOut = new LoginAndOut();
        loginAndOut.setUserid(userDto.getUserid());
        loginAndOut.setActiveCount(channelConcurrentMap.size());
        send.setData(loginAndOut);
        for (String s : channelConcurrentMap.keySet()) {
            channelConcurrentMap.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(send)));
        }

        ctx.close();
    }

    //清空所有画板
    private void ClearAllHandler(UserDto userDto, ChannelHandlerContext ctx) {
        ConcurrentMap<String, Channel> map = channelMap.get(userDto.getGroup());
        BasePushDto basePushDto = new BasePushDto();
        PushUserDto clearUsDto = new PushUserDto();
        clearUsDto.setUserid(userDto.getUserid());
        basePushDto.setData(clearUsDto);
        basePushDto.setType(9);
        for (String s : map.keySet()) {
            if(!s.equals(userDto.getUserid())) {//清除所有的画板不用发给自己
                map.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(basePushDto)));
            }
        }
        //清空画板缓存
        canvse.get(userDto.getGroup()).clear();
        
    }

    //清除自己的画板
    private void ClearUsHandler(UserDto userDto, ChannelHandlerContext ctx) {
        ConcurrentMap<String, Channel> map = channelMap.get(userDto.getGroup());
        BasePushDto basePushDto = new BasePushDto();
        PushUserDto clearUsDto = new PushUserDto();
        clearUsDto.setUserid(userDto.getUserid());
        basePushDto.setType(8);
        basePushDto.setData(clearUsDto);
        for (String s : map.keySet()) {
            if(!s.equals(userDto.getUserid())) {//清除自己的画板不用发给自己
                map.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(basePushDto)));
            }
        }
        //更新缓存
        WsUtil.ClearUsLocal(canvse,userDto.getUserid(),userDto.getGroup());

    }

    //移动背景图
    private void MoveImgHandler(UserDto userDto, ChannelHandlerContext ctx, MoveImgDto parseObject) {
        ConcurrentMap<String, Channel> map = channelMap.get(userDto.getGroup());
        BasePushDto basePushDto = new BasePushDto();
        basePushDto.setType(7);
        basePushDto.setData(parseObject);

        for (String s : map.keySet()) {
            if(!s.equals(userDto.getUserid())) {//移动背景不用发给自己
                map.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(basePushDto)));
            }
        }
        //更新移动背景缓存
        ImgDto imgDto = img.get(userDto.getGroup());
        if(null!=imgDto){
            imgDto.setX(parseObject.getX());
            imgDto.setY(parseObject.getY());
        }

    }

    //切换背景图
    private void ChangeImgHandler(UserDto userDto, ChannelHandlerContext ctx, ChangeImgDto parseObject) {
        //只在当前分组发
        ConcurrentMap<String, Channel> map = channelMap.get(userDto.getGroup());
        BasePushDto basePushDto = new BasePushDto();
        parseObject.setUserid(userDto.getUserid());
        basePushDto.setType(6);
        basePushDto.setData(parseObject);
        for (String s : map.keySet()) {
            if(!s.equals(userDto.getUserid())) {//切换背景不用发给自己
                map.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(basePushDto)));
            }
        }
        //更新背景图片缓存
        ImgDto imgDto = img.get(userDto.getGroup());
        if(null==imgDto){
            ImgDto imgDto1 = new ImgDto();
            imgDto1.setImgurl(parseObject.getUrl());
            imgDto1.setX(0);
            imgDto1.setY(0);
            img.put(userDto.getGroup(),imgDto1);
        }else{
            imgDto.setImgurl(parseObject.getUrl());
        }

    }

    //画板动作
    private void CanvasHandler(UserDto userDto, ChannelHandlerContext ctx, PullCanvasDto pullCanvasDto) {

        //缓存画板
        if( canvse.get(userDto.getGroup())==null){
            ArrayList<PullCanvasDto> c = new ArrayList<>();
            c.add(pullCanvasDto);
            canvse.put(userDto.getGroup(),c);
        }else{
            canvse.get(userDto.getGroup()).add(pullCanvasDto);
        }

        //只在当前分组发
        ConcurrentMap<String, Channel> map = channelMap.get(userDto.getGroup());
        BasePushDto send = new BasePushDto();
        send.setType(5);
        send.setData(pullCanvasDto);

        for (String s : map.keySet()) {
            if(!s.equals(userDto.getUserid())){//画板动作不用发给自己
                map.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(send)));
            }
        }
    }

    //发送消息
    private void MsgHandler(UserDto userDto, ChannelHandlerContext ctx, PullMsgDto pullMsgDto) {

        //只在当前分组发
        ConcurrentMap<String, Channel> map = channelMap.get(userDto.getGroup());
        BasePushDto send = new BasePushDto();
        send.setType(2);
        PushMsgDto sendMsgDto = new PushMsgDto();
        sendMsgDto.setMsg(pullMsgDto.getMsg());
        sendMsgDto.setUserid(userDto.getUserid());
        send.setData(sendMsgDto);
        for (String s : map.keySet()) {
                map.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(send)));
        }

    }

    //登录
    private void LoginHandler(ChannelHandlerContext ctx, LoginDto loginDto) {

        //登录
        if(loginDto.getUserid()!=null && null!=loginDto.getGroup()){
            //存入分组
            if(channelMap.get(loginDto.getGroup())==null){
                ConcurrentMap<String, Channel> map = new ConcurrentHashMap<>();
                map.put(loginDto.getUserid(),ctx.channel());
                channelMap.put(loginDto.getGroup(),map);
            }else{
                channelMap.get(loginDto.getGroup()).put(loginDto.getUserid(),ctx.channel());
            }
            UserDto userDto = new UserDto();
            userDto.setGroup(loginDto.getGroup());
            userDto.setUserid(loginDto.getUserid());
            channelByGroup.put( ctx.channel().id().asLongText(),userDto);
            //回复登录成功
            ctx.writeAndFlush(new TextWebSocketFrame(WsUtil.LoginSuccess()));
            //上线通知
            ConcurrentMap<String, Channel> channelConcurrentMap = channelMap.get(userDto.getGroup());
            BasePushDto send = new BasePushDto();
            send.setType(3);
            LoginAndOut loginAndOut = new LoginAndOut();
            loginAndOut.setUserid(userDto.getUserid());
            loginAndOut.setActiveCount(channelConcurrentMap.size());
            send.setData(loginAndOut);
            for (String s : channelConcurrentMap.keySet()) {
                channelConcurrentMap.get(s).writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(send)));
            }
        }else{
            ctx.close();
        }
    }

    /**
     * 异常处理
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("连接异常："+cause.getMessage());
        ctx.close();
    }



}
